package org.dxy.domain.handler.equipment;

import com.google.common.eventbus.EventBus;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dxy.domain.port.IEventRepository;
import org.dxy.domain.port.IdGenerator;
import org.dxy.domain.port.CommandHandler;
import org.dxy.domain.port.repository.IEquipmentRepository;
import org.dxy.domain.command.equipment.RegisterEquipmentCommand;
import org.dxy.domain.event.DomainEvent;
import org.dxy.domain.model.aggregate.Equipment;
import org.dxy.types.common.CommandResult;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.ArrayList;
import java.util.List;

/**
 * @description: 注册设备命令处理器
 * @author: dxy
 * @createTime: 2025/6/12 22:52
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class RegisterEquipmentCommandHandler implements CommandHandler<RegisterEquipmentCommand, Long> {

    private final IEquipmentRepository equipmentRepository;
    private final EventBus eventBus;
    private final IdGenerator idGenerator;
    private final IEventRepository IEventRepository;

    @Transactional
    @Override
    public CommandResult<Long> handle(RegisterEquipmentCommand command) {

        // 校验设备类型存在
//        if (!equipmentTypeRepository.exists(command.getEquipmentType())) {
//            throw new IllegalArgumentException("设备类型不存在");
//        }

        // 校验序列号唯一
        if (equipmentRepository.existsBySerialNumber(command.getSerialNumber())) {
            throw new IllegalArgumentException("设备序列号已存在");
        }

        // 1. 生成设备 ID
        Long equipmentId = idGenerator.generate();

        // 2. 创建聚合根并内部附带事件
        Equipment equipment = Equipment.register(equipmentId, command);

        // 3. 保存聚合根（可选实现事件持久化）
        equipmentRepository.save(equipment);

        IEventRepository.saveEvents(equipment.getDomainEvents());

        // 注册事务提交后的事件发布回调
        List<DomainEvent> events = new ArrayList<>(equipment.getDomainEvents());
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                // 提交成功后再发布事件
                events.forEach(eventBus::post);
            }
        });

        // 5. 清理事件，防止重复发布
        equipment.clearDomainEvents();

        log.info("设备注册成功, command={}", command);
        return CommandResult.success(equipmentId, "设备注册成功");
    }

}
